﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xunit;
using NSubstitute;
using Xunit.Extensions;
using System.Threading.Tasks;

namespace MetaSharp.Transformation.Tests.Patterns
{
	public class ValueTests
    {
        enum TestEnum1 { Success, Fail }

        [Theory]
        [InlineData('a')]
        [InlineData((byte)8)]
        [InlineData((short)16)]
        [InlineData((int)32)]
        [InlineData((long)64)]
        [InlineData((float)7.11f)]
        [InlineData((double)7.11d)]
        [InlineData(true)]
        [InlineData(TestEnum1.Success)]
		public async Task CanReadValues(object value)
		{
			var p = Pattern.Value(value);
            var m = await Pattern.Match(p, value);
			Assert.Equal(value, m.Value);
		}

		[Fact]
		public async Task CanReadDecimal()
        {
            var value = 7.11M;
            var p = Pattern.Value(value);
            var m = await Pattern.Match(p, value);
            Assert.Equal(value, m.Value);
        }

		[Fact]
		public async Task CanReadGuid()
        {
            var value = Guid.NewGuid();
            var p = Pattern.Value(value);
            var m = await Pattern.Match(p, value);
            Assert.Equal(value, m.Value);
        }

		[Fact]
		public async Task CanReadDateTime()
        {
            var value = DateTime.Now;
            var p = Pattern.Value(value);
            var m = await Pattern.Match(p, value);
            Assert.Equal(value, m.Value);
        }

		[Fact]
		public async Task CanReadObject()
        {
            var value = new object();
            var p = Pattern.Value(value);
            var m = await Pattern.Match(p, value);
            Assert.Equal(value, m.Value);
        }

		class TestClass1
		{
			public int Value { get; set; }
			public override bool Equals(object obj)
			{
				return (obj is TestClass1) && (this.Value == ((TestClass1)obj).Value);
			}

			public override int GetHashCode() { return this.Value; }
		}

		[Fact]
		public async Task CanReadCustom()
        {
            var value = new TestClass1 { Value = 7 };
            var p = Pattern.Value(value);
            var m = await Pattern.Match(p, value);
            Assert.Equal(value, m.Value);
        }

		[Fact]
		public async Task CanReadEmptyArray()
        {
            var value = new object[0];
            var p = Pattern.Value(value);
            var m = await Pattern.Match(p, new object[] { value });
            Assert.Equal(value, m.Value);
        }

		[Fact]
		public async Task CanReadNonEmptyArray()
		{
			var value = new object[] { 7, 11.13, "foo" };
            var p = Pattern.Value(value);
            var m = await Pattern.Match(p, new object[] { value });
            Assert.Equal(value, m.Value);
        }

		[Fact]
		public async Task CanReadBoxedValue()
		{
			object value = 7.11;
            var p = Pattern.Value(value);
            var m = await Pattern.Match(p, value);
            Assert.Equal(value, m.Value);
        }

		[Fact]
		public async Task CanReadNull()
        {
            object value = null;
            var p = Pattern.Value(value);
            var m = await Pattern.Match(p, value);
            Assert.Equal(value, m.Value);
        }

		[Fact]
		public async Task ValueIsNullFails()
		{
			var value = new object();
            var p = Pattern.Value<object>(null);
            var m = await Pattern.Match(p, value);
			Assert.False(m.Matched);
		}

		[Fact]
		public async Task InputIsNullFails()
        {
            var value = default(object);
            var p = Pattern.Value(7.11);
            var m = await Pattern.Match(p, value);
            Assert.False(m.Matched);
        }

		[Fact]
		public async Task ValuesDontMatchFails()
        {
            var p = Pattern.Value(11);
            var m = await Pattern.Match(p, 7);
            Assert.False(m.Matched);
        }

		[Fact]
		public async Task ValueTypesDontMatchFails()
        {
            var value = 7;
            var p = Pattern.Value(7.0);
            var m = await Pattern.Match(p, value);
            Assert.False(m.Matched);
        }
	}
}
